﻿using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using CoreGraphics;
using Foundation;
using Masonry;
using MyExtensions;
using ObjCRuntime;
using PagerManager;
using Ricardo.SDWebImage.iOS;
using UIKit;

namespace MyExtensions
{
    using System;
    using AVFoundation;
    using CoreGraphics;
    using mb;

    public static class Extension
    {
        public static UIViewController SetBackgroundColor(this UIViewController vc, UIColor color)
        {
            vc.View.BackgroundColor = color;
            return vc;
        }
        public static UIView SetParent(this UIView view, UIView parent)
        {
            parent.AddSubview(view);
            return view;
        }

        public static UIView GetSubViewByAID(this UIView view, string aid)
        {
            foreach (var v in view.Subviews)
            {
                if (v.AccessibilityIdentifier == aid)
                    return v;

                var fv = v.GetSubViewByAID(aid);
                if (fv != null)
                    return fv;
            }
            return null;
        }

        public static void PrintToConsole(this string str)
        {
            Console.WriteLine(str);
        }

        public static UIImage ToRetina(this UIImage image, int scale = 2)
        {
            return new UIImage(image.CGImage, scale, UIImageOrientation.Up);
        }

        public static UIImage WithColor(this UIImage image, UIColor color)
        {

            // UIGraphicsBeginImageContextWithOptions(size, false, scale)
            // let context = UIGraphicsGetCurrentContext() !
            //     context.translateBy(x: 0, y: size.height)
            // context.scaleBy(x: 1.0, y: -1.0)
            // context.setBlendMode(.normal)

            // let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
            // context.clip(to: rect, mask: cgImage!)

            // newColor.setFill()
            // context.fill(rect)

            // let newImage = UIGraphicsGetImageFromCurrentImageContext() !
            //     UIGraphicsEndImageContext()
            // newImage.accessibilityIdentifier = accessibilityIdentifier
            // return newImage
            UIGraphics.BeginImageContextWithOptions(image.Size, false, image.CurrentScale);
            var ctx = UIGraphics.GetCurrentContext();
            // ctx.TranslateCTM(image.Size.Width / 2, image.Size.Height / 2);
            ctx.SetBlendMode(CGBlendMode.Normal);
            var rect = new CGRect(0, 0, image.Size.Width, image.Size.Height);
            App.logger.Log("image with color", rect);
            ctx.ClipToMask(rect, image.CGImage);
            color.SetFill();
            ctx.FillRect(rect);
            var img = UIGraphics.GetImageFromCurrentImageContext();
            UIGraphics.EndImageContext();
            return img;

        }
    }
}

namespace mb.iOS
{

    unsafe public static class Util
    {
        public const string selAppearanceWhenContainedInInstancesOfClasses = "appearanceWhenContainedInInstancesOfClasses:";

        public static readonly IntPtr UIKitLibraryHandle = Dlfcn.dlopen("/System/Library/Frameworks/UIKit.framework/UIKit", 0);

        [DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
        public static extern IntPtr IntPtr_objc_msgSend_IntPtr(IntPtr receiver, IntPtr selector, IntPtr arg1);

        [DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
        public static extern void void_objc_msgSend_IntPtr(IntPtr receiver, IntPtr selector, IntPtr arg1);

        public static IntPtr GetAppearanceEx(IntPtr class_ptr, params Type[] whenFoundIn)
        {
            var ptrs = TypesToPointers(whenFoundIn);
            var handles = NSArray.FromIntPtrs(ptrs);
            using(var array = handles)
            {
                return IntPtr_objc_msgSend_IntPtr(class_ptr, Selector.GetHandle(selAppearanceWhenContainedInInstancesOfClasses), array.Handle);
            }
        }

        public static IntPtr[] TypesToPointers(Type[] whenFoundIn)
        {
            IntPtr[] ptrs = new IntPtr[whenFoundIn.Length];

            for (int i = 0; i < whenFoundIn.Length; i++)
            {
                if (whenFoundIn[i] == null)
                    throw new ArgumentException(String.Format("Parameter {0} was null, must specify a valid type", i));
                if (!typeof(NSObject).IsAssignableFrom(whenFoundIn[i]))
                    throw new ArgumentException(String.Format("Type {0} does not derive from NSObject", whenFoundIn[i]));

                var classHandle = Class.GetHandle(whenFoundIn[i]);
                if (classHandle == IntPtr.Zero)
                    throw new ArgumentException(string.Format("Could not find the Objective-C class for {0}", whenFoundIn[i].FullName));
                ptrs[i] = classHandle;
            }
            return ptrs;
        }

        public static void SetSearchBar()
        {
            var NSForegroundColorAttributeName = ObjCRuntime.Dlfcn.GetStringConstant(Util.UIKitLibraryHandle, "NSForegroundColorAttributeName");
            var defaultAttributes = NSDictionary.FromObjectsAndKeys(new NSObject[] { UIColor.Red }, new NSObject[] { NSForegroundColorAttributeName });
            var styleHandle = Util.GetAppearanceEx(Class.GetHandle("UITextField"), typeof(UISearchBar));
            Util.void_objc_msgSend_IntPtr(styleHandle, Selector.GetHandle("setDefaultTextAttributes:"), defaultAttributes.Handle);
        }

        public static string AddrOfObjectxx(object obj)
        {
            GCHandle objHandle = GCHandle.Alloc(obj, GCHandleType.WeakTrackResurrection);
            int address = GCHandle.ToIntPtr(objHandle).ToInt32();
            return "hd:" + address.ToString("X");
        }
        public static string AddrOfObject(object obj)
        {
            string ss = obj.ToString();

            // return ss;
            return "0x" + obj.GetHashCode().ToString("X");
            // TypedReference tr = __makeref(obj);
            // IntPtr ptr = * * (IntPtr * * ) ( & tr);
            // return ptr.ToString("X");
        }

        public static void SetUIImageViewUrl(UIImageView imgView, string url)
        {
            var nstr = new NSString(url);
            var urlstr = nstr.CreateStringByAddingPercentEncoding(NSUrlUtilities_NSCharacterSet.UrlFragmentAllowedCharacterSet);
            if (url.IndexOf('%') >= 0)
                urlstr = nstr;
            // App.logger.Log("sdwebimage", urlstr);
            imgView.Sd_setImageWithURL(new NSUrl(urlstr));
        }

        public static NSUrl EncodeStringToUrl(string url)
        {
            var nstr = new NSString(url);
            var urlstr = nstr.CreateStringByAddingPercentEncoding(NSUrlUtilities_NSCharacterSet.UrlFragmentAllowedCharacterSet);
            return new NSUrl(urlstr);
        }

        public static bool IsSimulator()
        {
            return ObjCRuntime.Runtime.Arch.ToString() == "SIMULATOR";
        }

    }

    public class MyPopupManager
    {
        public enum Mode
        {
            OK,
            YESNO,
        }

        public static void ShowPopView(UIView view, float percentWidth = 0.7f, float percentHeight = 0.5f, Action onClickOut = null)
        {
            var vc = new UIViewController();
            vc.View.BackgroundColor = UIColor.Black.ColorWithAlpha(0.5f);
            vc.ModalPresentationStyle = UIModalPresentationStyle.OverFullScreen;
            var btn = new UIButton();
            btn.SetParent(vc.View);
            btn.MakeConstraints(m => m.Edges.EqualTo(vc.View));
            btn.TouchUpInside += (s, e) => onClickOut?.Invoke();
            view.SetParent(vc.View);
            // view.Layer.CornerRadius = 30;

            App.logger.Log("showpop", percentWidth, percentHeight);
            view.MakeConstraints(m =>
            {
                m.Center.EqualTo(vc.View);
                if (percentWidth <= 1)
                    m.Width.EqualTo(vc.View).MultipliedBy(percentWidth);
                else
                    m.Width.EqualTo(NSObject.FromObject(percentWidth));

                if (percentHeight <= 1)
                    m.Height.EqualTo(vc.View).MultipliedBy(percentHeight);
                else
                    m.Height.EqualTo(NSObject.FromObject(percentHeight));
            });
            App.logger.Log("view.Frame.Width:" + view.Frame.Width);
            App.logger.Log("view.Frame.Height:" + view.Frame.Height);
            iOS.AppDelegate.Instance.NavController.PresentViewController(vc, false, null);
        }

        public static void HidePopView()
        {
            iOS.AppDelegate.Instance.NavController.DismissViewController(true, null);
        }

        public static async Task<bool> ShowYesNo(string msg, string[] btnText = null, Action<bool> onClick = null)
        {
            var baseView = CreateBaseView(2);
            var bkImgView = baseView.Subviews[0] as UIImageView;
            var lab = baseView.Subviews[1] as UILabel;
            var btnNo = baseView.Subviews[2] as UIButton;
            var btnYes = baseView.Subviews[3] as UIButton;

            lab.Text = msg;
            btnNo.SetTitle(btnText?[0] ?? "否", UIControlState.Normal);
            btnYes.SetTitle(btnText?[1] ?? "是", UIControlState.Normal);

            var promise = new TaskCompletionSource<bool>();
            btnNo.TouchUpInside += delegate
            {
                HidePopView();
                onClick?.Invoke(false);
                promise.TrySetResult(false);
            };
            btnYes.TouchUpInside += delegate
            {
                HidePopView();
                onClick?.Invoke(true);
                promise.TrySetResult(true);
            };
            ShowPopView(baseView, (float) bkImgView.Image.Size.Width, (float) bkImgView.Image.Size.Height);

            bool sel = await promise.Task;
            return sel;
        }
        public static async Task ShowMsgBox(string msg, string btnText = "好的", Action onClick = null)
        {
            var baseView = CreateBaseView(1);
            var bkImgView = baseView.Subviews[0] as UIImageView;
            var lab = baseView.Subviews[1] as UILabel;
            var btn = baseView.Subviews[2] as UIButton;

            btn.TouchUpInside += (s, e) =>
            {
                onClick?.Invoke();
            };
            btn.SetTitle(btnText, UIControlState.Normal);
            lab.Text = msg;
            ShowPopView(baseView, (float) bkImgView.Image.Size.Width, (float) bkImgView.Image.Size.Height, onClickOut: () =>
            {
                // App.HidePopView();
            });

            var promise = new TaskCompletionSource<bool>();
            btn.TouchUpInside += delegate
            {
                promise.TrySetResult(true);
            };
            await promise.Task;
        }
        static UIView CreateBaseView(int btnCount)
        {
            var pv = new UIView();

            var bkImgView = new UIImageView();
            bkImgView.SetParent(pv);
            bkImgView.MakeConstraints(m => m.Edges.EqualTo(pv));
            bkImgView.Image = UIImage.FromBundle("popup/bg").ToRetina();

            var lab = new UILabel()
            {
                // BackgroundColor = UIColor.Green,
                LineBreakMode = UILineBreakMode.WordWrap,
                Lines = 0,
                TextAlignment = UITextAlignment.Center,
            };
            lab.SetParent(pv);
            lab.MakeConstraints(m =>
            {
                m.Center.EqualTo(pv);
                m.Width.EqualTo(pv).MultipliedBy(0.8f);
                m.Top.EqualTo(NSObject.FromObject(130));
                m.Bottom.EqualTo(pv).Offset(-40);
            });

            if (btnCount == 1)
            {
                var btn = new UIButton();
                btn.SetParent(pv);
                btn.SetBackgroundImage(UIImage.FromBundle("popup/botton"), UIControlState.Normal);
                btn.SetTitleColor(UIColor.Black, UIControlState.Normal);
                btn.MakeConstraints((m) =>
                {
                    m.CenterX.EqualTo(pv);
                    m.Bottom.EqualTo(pv).Offset(-10);
                    // m.Top.EqualTo(lab.Bottom()).Offset(10);
                });
            }
            else if (btnCount == 2)
            {
                float[] xpl = { 0.5f, 1.5f };
                for (int i = 0; i < btnCount; i++)
                {
                    var btn = new UIButton();
                    btn.SetParent(pv);
                    btn.SetBackgroundImage(UIImage.FromBundle("popup/botton"), UIControlState.Normal);
                    btn.SetTitleColor(UIColor.Black, UIControlState.Normal);
                    btn.MakeConstraints((m) =>
                    {
                        m.Bottom.EqualTo(pv).Offset(-10);
                        m.CenterX.EqualTo(pv).MultipliedBy(xpl[i]);
                        m.Width.EqualTo(NSObject.FromObject(100));
                    });
                }
            }
            return pv;
        }
    }

    public class MyUITextFieldDelegate : UITextFieldDelegate
    {
        public Func<UITextField, bool> MyShouldReturn;
        public override bool ShouldReturn(UITextField textField)
        {
            return MyShouldReturn?.Invoke(textField) ?? false;
        }

    }

    public class MyIUIPopoverPresentationControllerDelegate : NSObject, IUIPopoverPresentationControllerDelegate
    {

        public Func<UIPopoverPresentationController, bool> MyShouldDismissPopover;
        public Action MyBeforePop;
        public Action MyAfterPop;

        [Export("adaptivePresentationStyleForPresentationController:traitCollection:")]
        public UIModalPresentationStyle GetAdaptivePresentationStyle(UIPresentationController controller, UITraitCollection traitCollection)
        {
            return UIModalPresentationStyle.None;
        }

        [Export("popoverPresentationControllerShouldDismissPopover:")]
        public bool ShouldDismissPopover(UIPopoverPresentationController popoverPresentationController)
        {
            return MyShouldDismissPopover?.Invoke(popoverPresentationController) ?? true;
        }

        [Export("prepareForPopoverPresentation:")]
        public void PrepareForPopoverPresentation(UIPopoverPresentationController popoverPresentationController)
        {
            MyBeforePop?.Invoke();
        }

        [Export("popoverPresentationControllerDidDismissPopover:")]
        public void DidDismissPopover(UIPopoverPresentationController popoverPresentationController)
        {
            MyAfterPop?.Invoke();
        }
    }

    public class MyScrollViewDelegate : UIScrollViewDelegate
    {

    }
    public class MyScrollView : UIScrollView
    {
        static ILog logger = mb.ServiceLocator.Instance.Get<ILog>();
        public Func<MyScrollView, UIGestureRecognizer, UIGestureRecognizer, bool> MyShouldRecognizeSimultaneously;
        public Func<MyScrollView, UIGestureRecognizer, UIGestureRecognizer, bool> MyShouldRequireFailureOf;
        public Action MyLayoutSubviews;

        [Foundation.Export("gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:")]
        public bool ShouldRecognizeSimultaneously(UIKit.UIGestureRecognizer gestureRecognizer, UIKit.UIGestureRecognizer otherGestureRecognizer)
        {
            if (MyShouldRecognizeSimultaneously != null)
                return MyShouldRecognizeSimultaneously(this, gestureRecognizer, otherGestureRecognizer);
            return false;
        }

        [Export("gestureRecognizer:shouldRequireFailureOfGestureRecognizer:")]
        public virtual bool ShouldRequireFailureOf(UIGestureRecognizer gestureRecognizer, UIGestureRecognizer otherGestureRecognizer)
        {
            if (MyShouldRequireFailureOf != null)
                return MyShouldRequireFailureOf(this, gestureRecognizer, otherGestureRecognizer);
            return false;
        }

        public override void LayoutSubviews()
        {
            MyLayoutSubviews?.Invoke();
        }
    }

    public class PageViewController : UIViewController, IPageViewController
    {
        #region Fields

        private readonly string _labelText = "hellow";
        private readonly Action _action1;
        private readonly Action _action2;

        #endregion

        public PageViewController(string labelText)
        {
            _labelText = labelText;
        }

        public UIBarButtonItem RightBarButtonItem => null;

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            var lblCentral = new UILabel(new CGRect(0, 0, 134f, 26f));
            lblCentral.TextColor = UIColor.White;
            lblCentral.Center = View.Center;
            lblCentral.Text = _labelText;
            View.AddSubview(lblCentral);

            var btnAction1 = new UIButton(new CGRect(0, 0, 100f, 30f));
            btnAction1.SetTitle("Action1", UIControlState.Normal);
            btnAction1.Center = new CGPoint(View.Center.X, View.Center.Y + 50f);
            btnAction1.TouchUpInside += BtnAction1OnTouchUpInside;
            View.AddSubview(btnAction1);
            btnAction1.MakeConstraints(m =>
            {
                m.Bottom.EqualTo(View).Offset(-20);
            });

            var btnAction2 = new UIButton(new CGRect(0, 0, 100f, 30f));
            btnAction2.SetTitle("Action2", UIControlState.Normal);
            btnAction2.Center = new CGPoint(View.Center.X, View.Center.Y + 100f);
            btnAction2.TouchUpInside += BtnAction2OnTouchUpInside;
            View.AddSubview(btnAction2);
            btnAction2.MakeConstraints(m =>
            {
                m.Bottom.EqualTo(View).Offset(-60);
            });
        }

        public void Refresh()
        {
            // Load vc data here
        }

        private void BtnAction2OnTouchUpInside(object sender, EventArgs e)
        {
            _action2();
        }

        private void BtnAction1OnTouchUpInside(object sender, EventArgs e)
        {
            _action1();
        }
    }

    public class MyVideoView : UIView
    {
        [Export("layerClass")]
        public static Class LayerClass()
        {
            return new Class(typeof(AVFoundation.AVPlayerLayer));
        }

        public Action MyLayoutSubviews;
        public override void LayoutSubviews()
        {
            MyLayoutSubviews?.Invoke();
        }
    }

}

namespace mb
{
    public static partial class Util
    {
        public static string ReadBuiltinFile(string path)
        {
            string content = null;
            try
            {
                content = System.IO.File.ReadAllText(path);
                return content;
            }
            catch (System.Exception)
            {
                App.logger.Log("ReadBuiltinFile fail", path);
                return content;
            }
        }
        public static UIImage MakeColorImage(CGSize size, UIColor color)
        {
            // func imageWithSize(size: CGSize, filledWithColor color : UIColor = UIColor.clearColor(), scale : CGFloat = 0.0, opaque : Bool = false) - > UIImage
            // {
            //     let rect = CGRectMake(0, 0, size.width, size.height)

            //     UIGraphicsBeginImageContextWithOptions(size, opaque, scale)
            //     color.set()
            //     UIRectFill(rect)
            //     let image = UIGraphicsGetImageFromCurrentImageContext()
            //     UIGraphicsEndImageContext()

            //     return image
            // }

            UIGraphics.BeginImageContextWithOptions(size, false, 1.0f);
            var ctx = UIGraphics.GetCurrentContext();
            App.logger.Log("makeColorImage", ctx);
            var rect = new CGRect(0, 0, size.Width, size.Height);
            color.SetFill();
            ctx.FillRect(rect);
            var img = UIGraphics.GetImageFromCurrentImageContext();
            UIGraphics.EndImageContext();
            return img;
        }
    }
}